<?php
/**
 * Notes:
 * User: wudg <544038230@qq.com>
 * Date: 2025/3/31 13:45
 */

namespace App\Service\User;


use App\Components\Logs\LogAgent;
use App\Components\Logs\LogFactory;
use App\Components\Logs\LogImpl;
use App\Constants\System\SysStatusConst;
use App\Constants\User\AuthMiniTypeConst;
use App\Constants\User\UserAccountDefaultConst;
use App\Constants\User\UserAccountTypeConst;
use App\Constants\User\UserSexConst;
use App\Constants\User\UserStatusConst;
use App\Constants\User\UserTypeConst;
use App\Dao\Users\UsersAccountDao;
use App\Dao\Users\UsersDao;
use App\Dao\Users\UsersMiniAuthDao;
use App\Events\AfterRegisterHandle;
use App\Exception\ServiceException;
use App\Model\Users\User;
use App\Model\Users\UsersAccount;
use App\Model\Users\UsersMiniAuth;
use App\Utils\HelperUtils;
use App\Utils\RequestHeaderUtil;
use Hyperf\Database\Model\Model;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Qbhy\HyperfAuth\AuthManager;
use Exception;
use Psr\EventDispatcher\EventDispatcherInterface;
class AuthService
{


    #[Inject]
    protected UsersDao $usersDao;


    #[Inject]
    protected UsersMiniAuthDao $usersMiniAuthDao;


    #[Inject]
    protected AuthManager $authManager;



    #[Inject]
    protected LogImpl $logImpl;


    #[Inject]
    protected UsersAccountDao $usersAccountDao;


    #[Inject]
    private EventDispatcherInterface $eventDispatcher;

    /**
     * 用户注册
     * @param array $data
     * @param int $softId
     * @return \Hyperf\Database\Model\Model
     */
    public function register(array $data,int $softId = 0)
    {
        $userInfo = $this->usersDao->getInfoByAccount($data['account']);

        if($userInfo) throw new ServiceException("账号已存在，请更换！");


        $dbData = [
            'account' => trim($data['account']),
            'password' =>!empty($data['password']) ? password_hash(trim($data['password']),PASSWORD_DEFAULT) : "",
            'nick_name' => $data['nick_name'] ?? "",
            'company_name' => $data['company_name'] ?? "",
            'name' => $data['name'] ?? "",
            'soft_id' => $softId,
            'avatar' => $data['avatar'] ?? "",
            'birthday' => $data['birthday'] ?? null,
            'sex' => $data['sex'] ?? UserSexConst::SEX_UNKNOWN->value,
            'email' => $data['email'] ?? "",
            'tel' => $data['tel'] ?? "",
            'phone' => $data['phone'] ?? "",
            'config' => $data['config'] ?? "{}",
            'remark' => "",
            'last_login_ip' => "",
            'status' =>  SysStatusConst::NORMAL->value,
            'last_login_time' => null,
            'user_type' => !empty($data['user_type']) ?  (int)$data['user_type'] : UserTypeConst::MAIN_ACCOUNT->value,
        ];
        $userModel = new User();
        $userInfo = $this->usersDao->add($userModel,$dbData);

        if($softId == 0) {
            $userInfo->soft_id =$userInfo->id;
            $userInfo->save();
        }

        $this->eventDispatcher->dispatch(new AfterRegisterHandle($userInfo));


        return $userInfo;
    }

    /**
     * 绑定 openId 账号
     * @param array $params
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function bindUidAccount(array $params)
    {
        $userAuthInfo = $this->usersMiniAuthDao->getIdByPk($params['bind_id']);

        if(!$userAuthInfo) throw new ServiceException("绑定信息不存在");

        try {

            $registerData = [
                'account' => $params['account'],
                'nick_name' => "普通用户",
            ];

            if( HelperUtils::isMobile($params['account']))
            {
               $registerData['phone'] = $params['account'];
            }

            if(!empty($params['password']))
            {
                $registerData['password'] = password_hash(trim($params['password']),PASSWORD_DEFAULT);
            }

            $userIsset = $this->usersDao->getInfoByAccount($params['account']);

            if($userIsset) throw new ServiceException("账号已存在，请更换");
            Db::beginTransaction();

                $userInfo = $this->register($registerData);
                $this->usersMiniAuthDao->edit($userAuthInfo,[
                    'uid' => $userInfo->id,
                ]);
            Db::commit();

            $loginLogData = LogFactory::saveLoginLog($userInfo->id,$userInfo->account,'Y','小程序登录系统');
            /**
             * 写入登录日志
             */
            $this->logImpl->saveLoginLog($loginLogData);
            return $this->loginByUserInfo($userInfo,true);
        }catch (Exception $e)
        {
            Db::rollBack();
            throw new ServiceException($e->getMessage());
        }
    }

    /**
     * 微信小程序登录
     * @param string $code
     * @param int $softId
     * @param int $accountId
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function wxCodeLogin(string $code,int $softId = 0,int $accountId = 0)
    {
        try
        {
            $app = HelperUtils::miniProgram();
            $utils = $app->getUtils();
            $response = $utils->codeToSession($code);
            if(!isset($response['openid'])) throw new ServiceException("登录失败");
            $userAuthInfo = $this->usersMiniAuthDao->getCode($response['openid']);
            if(!$userAuthInfo)
            {
                $registerData = [
                    'account' => $response['openid'],
                    'password' => "",
                    'nick_name' => "微信用户",
                ];
                //子账号角色
                if(!empty($softId))
                {
                    $registerData['user_type'] = UserTypeConst::SUB_ACCOUNT->value;
                }

                if(!empty($accountId))
                {
                    $userAccountInfo = $this->usersAccountDao->getInfoByPk($accountId);

                    if(!$userAccountInfo) throw new ServiceException("账号不存在");
                    $registerData['config'] = json_encode(['account_id' => $userAccountInfo->id]);
                }
                try {
                    Db::beginTransaction();
                    $userInfo = $this->register($registerData,$softId);
                    $this->usersMiniAuthDao->add(new UsersMiniAuth(),[
                        'uid' => $userInfo->id,
                        'type' => AuthMiniTypeConst::WX_MINI,
                        'openid' => $response['openid'],
                        'unionid' => !empty($response['unionid']) ?$response['unionid'] : $response['openid'],
                    ]);
                    Db::commit();
                }catch (Exception $e)
                {
                    Db::rollBack();
                    throw new ServiceException($e->getMessage());
                }
            }else{
                if(empty($userAuthInfo->user)) {
                    return [false,$userAuthInfo->toArray()];
                }
                $userInfo = $userAuthInfo->user;
            }
            $loginLogData = LogFactory::saveLoginLog($userInfo->id,$userInfo->account,'Y','小程序登录系统');
            /**
             * 写入登录日志
             */
            $this->logImpl->saveLoginLog($loginLogData);
            return $this->loginByUserInfo($userInfo,true);
        }catch (Exception $e)
        {
            throw new ServiceException("登录失败：".$e->getMessage());
        }

    }



    /**
     * 账号登录
     * @param string $account
     * @param string $password
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function login(string $account,string $password=null)
    {
        if(HelperUtils::isMobile($account))
        {
            $userInfo = $this->usersDao->getInfoByPhone($account);
        }else{
            $userInfo = $this->usersDao->getInfoByAccount($account);
        }
        if(!$userInfo) {
            LogAgent::getInstance('event','userLogin')->info("用户{$account} 登录失败,用户不存在");
            throw new ServiceException("用户不存在");
        }
        $loginLogData = LogFactory::saveLoginLog($userInfo->id,$userInfo->account);
        if($userInfo->status != SysStatusConst::NORMAL->value)
        {
            $statusName = UserStatusConst::getMessage($userInfo->status);
            LogAgent::getInstance('event','userLogin')->info("用户{$userInfo->account} 登录时状态为{$statusName},禁止登录");
            $loginLogData['message'] = "登录状态异常，账号状态为:{$statusName}";
            $loginLogData['success'] = 'N';
            $this->logImpl->saveLoginLog($loginLogData);
            throw new ServiceException("账号异常，联系管理员处理！");
        }
        if(!empty($password) && !password_verify($password,$userInfo->password))
        {
            LogAgent::getInstance('event','userLogin')->info("用户{$userInfo->account} 登录时密码错误,禁止登录");
            $loginLogData['success'] = 'N';
            $loginLogData['message'] = "登录异常，密码错误";
            $this->logImpl->saveLoginLog($loginLogData);
            throw new ServiceException("密码错误！");
        }
        /**
         * 写入登录日志
         */
        $this->logImpl->saveLoginLog($loginLogData);
        return $this->loginByUserInfo($userInfo,true);

    }


    public function loginOut()
    {
        auth()->logout();
    }


    /**
     * 用户信息直接登录
     * @param $userInfo
     * @param bool $saveLog
     * @return array
     */
    public function loginByUserInfo($userInfo,bool $saveLog = false)
    {
        if($saveLog)
        {
            $loginLogData = LogFactory::saveLoginLog($userInfo->id,$userInfo->account);
            /**
             * 写入登录日志
             */
            $this->logImpl->saveLoginLog($loginLogData);
        }
        $token = $this->authManager->guard('sso')->login($userInfo);
        $userInfo->last_login_ip = RequestHeaderUtil::getClientIp();
        $userInfo->last_login_time = date("Y-m-d H:i:s");
        $userInfo->save();
        return [$token,$userInfo];
    }

}